比较全面的水平垂直居中方案。水平垂直居中问题大体分为两类,一类目标元素是行内元素,一类目标元素是块级元素(其中,块级元素又包括定宽高和不定宽高)。
1.水平居中方案
1.1 行内元素水平居中
把该行内元素包裹在一个块级父元素中,之后设置父元素:
.parent{
text-align:center
}
1.2 块级元素水平居中
设置该元素:
div{
width: 100px; /* 注意宽度一定要给出 */
margin: 0 auto; /* auto 是必须的 */
}
1.3 多个块级元素水平居中
- 转换为行内元素。设置目标块级元素
display:inline-block
,之后设置父元素:
.parent{
text-align:center
}
- 利用弹性盒子。设置父元素:
.parent{
display:flex;
justify-content: center;
}
2.垂直居中方案
2.1 块级父元素高度已知,行内子元素为单行
设置父元素:
.parent{
/* 设置父元素的高度等于行高 */
height:100px;
line-height:100px;
}
Tip):这里的 line-height
最终是通过继承作用在子元素上的,所以也可以直接设置子元素为 line-height:100px
。
2.2 块级父元素高度已知,行内子元素为多行
设置父元素:
.parent{
display:table-cell;
vertical-align:middle;
height:100px;
}
Tip:注意父元素得有高度,否则默认高度由子元素撑起,就没有垂直居中的说法了。
2.3 块级父元素高度未设置,子元素为行内或块级
设置父元素:
.parent{
padding-top:10px;
padding-bottom:10px;
}
2.4 块级子元素高度已知
设置父元素:
.parent{
position:relative;
}
设置子元素:
div{
position:absolute;
top: 50%;
height: 100px;
margin-top: -50px;
}
/* 或者直接 */
div{
position:absolute;
top: calc(50% - 50px);
height: 100px;
}
Tip:原理是绝对定位。top:50%
确保了子元素位于父元素 1/2 分割线以下,margin-top: -50px
代表子元素在这个基础上上移自身的一半高度,此时子元素与父元素中线重合,实现垂直居中。
2.5 块级子元素高度未知
虽然我们不知道子元素高度,但可以确定必定是在 top:50%
的基础上,上移自身的一半高度,这里可以改用 transform: translateY(-50%);
div{
position:absolute;
top: 50%;
height: 100px;
transfrom: translateY(-50%);
}
3.水平垂直居中方案
3.1 已知高度和宽度的元素
- 方法一:
设置父元素:
.parent{
position: relative;
}
设置目标元素:
div{
position:absolute;
width:100px;
height: 100px;
margin:auto;
top:0;
bottom:0;
left:0;
right:0;
}
Tip:这段代码比较优美和灵活。原理其实是:子元素依然相对于父元素定位,但是由于 top:0
和 bottom:0
无法同时满足,且该元素的 margin
又是自适应,因此最终变成了由上下外边距平分尺寸,从而达到垂直居中。至于水平居中,原理也是一样。
- 方法二:
设置父元素:
.parent{
position: relative;
}
设置目标元素:
div{
position:absolute;
width:100px;
height: 50px;
top: 50%;
left:50%;
margin-top: -25px;
margin-left: -50px;
}
Tip):原理和 2.3 其实一样,只是现在多了一个水平方向的居中。看下图:
或者通过 calc()
一次性设置目标元素的平移距离:
div{
position:absolute;
width:100px;
height: 50px;
top: calc(50% - 25px);
left:calc(50% - 50px);
}
3.2 未知高度和宽度的元素
设置父元素:
.parent{
position: relative;
}
设置目标元素:
div{
position:absolute;
width:100px;
height: 50px;
top: 50%;
left:50%;
transform: translate(-50%,-50%);
}
Tip:原理和 2.4 一样,不同的是我们现在不知道子元素的宽高,也就不知道要在 top:50%
和 left:50%
的基础上再移动多少距离,但可以确定一定是移动自身宽高的一半,因此把 margin-top:-25px
和 margin-left:-50px
对应改为 transform: translate(-50%,-50%)
3.3 任意元素
- 3.3.1 利用弹性布局一
设置父元素:
.parent{
display:flex;
justify-content: center;
align-items: center;
}
- 3.3.2 利用弹性布局二
设置父元素:
.parent{
display: flex;
}
设置子元素:
div{
margin: auto;
}
- 3.3.3 利用网格布局一
设置父元素:
.parent{
display: grid;
}
设置子元素:
div{
justify-self:center;
align-self:center;
}
- 3.3.4 利用网格布局二
设置父元素:
.parent{
display: grid;
}
设置子元素:
div{
margin: auto;
}
- 3.3.5 利用伪元素
设置父元素
.parent {
font-size: 0; /* 消除空隙 */
text-align: center; /* 实现水平居中*/
&::before {
content: "";
display: inline-block;
width: 0;
height: 100%;
vertical-align: middle;
}
}
设置子元素
div{
display: inline-block;
vertical-align: middle;
}
参考:
https://segmentfault.com/a/1190000003761600
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/92